package org.GenusApis.lib;

import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;

import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;

public class OAuthUtil {
    public static String normalizeKeyValueParameters(HashMap<String, String> params) throws UnsupportedEncodingException {
        Map<String, String> sortedParams = new TreeMap<String, String>(params);

        ArrayList<String> encodedVars = new ArrayList<String>();
        for (Map.Entry<String, String> entry : sortedParams.entrySet()) {
            String key = OAuthUtil.urlencodeRFC3986_UTF8(entry.getKey());
            String value = OAuthUtil.urlencodeRFC3986_UTF8(entry.getValue());;
            String encodedVar = key + "=" + value;
            encodedVars.add(encodedVar);
        }
        
        StringBuilder normalized = new StringBuilder();
        for (String encodedVar : encodedVars) {
            if (normalized.length() > 0) {
                normalized.append("&");
            }
            normalized.append(encodedVar);
        }
        return normalized.toString();
    }
    
    public static String urlencodeRFC3986(String string) {
        return URLEncoder.encode(string)
        // RFC3986 compatible.
        .replace("+", "%20").replace("*", "%2A")
        .replace("%7E", "~");        
    }
    
    public static String urlencodeRFC3986_UTF8(String string) throws UnsupportedEncodingException {
        return URLEncoder.encode(string, "UTF-8")
        // RFC3986 compatible.
        .replace("+", "%20").replace("*", "%2A")
        .replace("%7E", "~");        
    }
    
    public static String urldecodeRFC3986(String string) {
        return URLDecoder.decode(string);
    }
    
    public static String urldecodeRFC3986_UTF8(String string) throws UnsupportedEncodingException {
        return URLDecoder.decode(string, "UTF-8");
    }
    
    public static String generateBaseString(String httpMethod, String uri, String params) throws UnsupportedEncodingException {
        StringBuilder baseString = new StringBuilder();
        baseString.append(OAuthUtil.urlencodeRFC3986_UTF8(httpMethod));
        baseString.append('&');
        baseString.append(OAuthUtil.urlencodeRFC3986_UTF8(uri));
        baseString.append('&');
        baseString.append(OAuthUtil.urlencodeRFC3986_UTF8(params));
        return baseString.toString();
    }
    
    public static String calculateHMACSHA1Signature(String baseString, String consumerSecret, String tokenSecret) throws UnsupportedEncodingException {
        StringBuilder hmacKey = new StringBuilder();
        hmacKey.append(OAuthUtil.urlencodeRFC3986_UTF8(consumerSecret));
        hmacKey.append('&');
        hmacKey.append(OAuthUtil.urlencodeRFC3986_UTF8(tokenSecret));
        SecretKey key = new SecretKeySpec(hmacKey.toString().getBytes(), "HmacSHA1");
        
        Mac mac;
        try {
            mac = Mac.getInstance("HmacSHA1");
            mac.init(key);
            byte[] signatureBytes = mac.doFinal(baseString.getBytes());
            return new String(Base64Coder.encode(signatureBytes));
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        }
        return "";
    }
    
    public static StringEntity getRFC2875EncodedStringEntity(List<BasicNameValuePair> nameValuePairs) throws UnsupportedEncodingException {
        // RFC3986 compatible
        String string = URLEncodedUtils.format(nameValuePairs, "UTF-8")
            .replace("+", "%20").replace("*", "%2A")
            .replace("%7E", "~");
        return new StringEntity(string);
    }
}
